package tau.dimes.visualization.applet;

import processing.core.PApplet;

/**
 * Represents the applet's internal clock.
 */
class Clock
{
	private final PApplet applet;
	private final float interval;
	private final float maximum;

	private float current;
	private float lastMillis;
	private boolean running;

	private int counter;

	/**
	 * Constructs a new Clock.
	 * @param applet A reference to the containing applet.
	 * @param interval The length of one time slot.
	 * @param timeSlots The number of time slots.
	 */
	Clock(PApplet applet, float interval, int timeSlots)
	{
		this.applet = applet;
		this.interval = interval;
		this.maximum = timeSlots * interval;
		reset();
	}

	/**
	 * Resets the clock.
	 */
	void reset()
	{
		this.current = 0;
		this.running = false;
	}

	/**
	 * Causes the clock to start running.
	 */
	void start()
	{
		if (current < maximum)
		{
			running = true;
			lastMillis = applet.millis();
			applet.loop();
		}
	}

	/**
	 * Causes the clock to stop running.
	 */
	void stop()
	{
		running = false;
		applet.noLoop();
	}

	/**
	 * Causes the clock to update.
	 */
	void update()
	{
		if (running)
		{
			float millis = applet.millis();
			float delta;

			if (!Parameters.aviRecord())
				delta = millis - lastMillis;
			else
				delta = 1000F / Parameters.getFps();

			current = PApplet.constrain(current + delta, 0, maximum);
			lastMillis = millis;

			counter++;

			if (getCurrentMillis() == maximum)
				stop();
		}
	}
	
	/**
	 * Gets a value indicating whether the clock is running.
	 * @return True if the clock is running, otherwise false.
	 */
	boolean isRunning()
	{
		return running;
	}

	/**
	 * Gets the number of milliseconds passed.
	 * @return The number of milliseconds passed.
	 */
	float getCurrentMillis()
	{
		return current;
	}

	/**
	 * Gets the current time slot.
	 * @return The current time slot.
	 */
	int getTimeSlot()
	{
		if ((current / interval) % 1 != 0.0F)
			return (int) Math.floor(current / interval);
		else
			return (int) Math.max(0, (current / interval) - 1);
	}

	/**
	 * Gets a value between 0-1 representing the current position inside the time slot.
	 * @return A value between 0-1 representing the current position inside the time slot.
	 */
	float getAlpha()
	{
		float fullAlpha = current / interval;

		if (fullAlpha % 1 != 0.0F)
			return fullAlpha % 1F;
		else if (fullAlpha == 0)
			return 0;
		else
			return 1;
	}
}
